#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Aug 24 16:32:47 2017

@author: XFBY

"""

import math
from numpy import *

# 导入数据集
def loadDataSet():
	dataMat = []
	labelMat = []
	fr = open('testSet.txt')
	for line in fr.readlines():
		lineArr = line.strip().split()
		dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
		labelMat.append(int(lineArr[2]))
	return dataMat, labelMat

# sigmoid函数
def sigmoid(inX):
	return 1.0 / (1 + exp(-inX))

# 梯度上升法
def gradAscent(dataMatIn, classLabels):
	# 转换为numpy矩阵数据类型
	dataMatrix = mat(dataMatIn)
	labelMat = mat(classLabels).transpose()
	m, n = shape(dataMatrix)
	alpha = 0.001	# 步长
	maxCycles = 500	# 迭代500次
	weights = ones((n, 1))	# 权值
	for k in range(maxCycles):
		h = sigmoid(dataMatrix*weights)
		error = labelMat - h
		weights = weights + alpha * dataMatrix.transpose() * error
	return weights

# 画出数据集和logistic回归的最佳拟合直线的函数
def plotBestFit(weights):
	import matplotlib.pyplot as plt
	dataMat, labelMat = loadDataSet()
	dataArr = array(dataMat)
	n = shape(dataArr)[0]
	xcord1 = []
	ycord1 = []
	xcord2 = []
	ycord2 = []
	for i in range(n):
		if int(labelMat[i]) == 1:
			xcord1.append(dataArr[i, 1])
			ycord1.append(dataArr[i, 2])
		else:
			xcord2.append(dataArr[i, 1])
			ycord2.append(dataArr[i, 2])
	fig = plt.figure()
	ax = fig.add_subplot(111)
	ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
	ax.scatter(xcord2, ycord2, s=30, c='green')
	x = arange(-3.0, 3.0, 0.1)
#	x = mat(x).transpose
	y = (-weights[0] - weights[1] * x) / weights[2]  
	y = array(y)
	ax.plot(x, y[0])
	plt.xlabel('X')
	plt.ylabel('y')
	plt.show()
# 随机梯度上升算法
def stocGradAscent(dataMatIn, classLabels):
	# 转换为numpy矩阵数据类型
	dataMatrix = mat(dataMatIn)
	labelMat = mat(classLabels).transpose()
	m,n = shape(dataMatrix)
	alpha = 0.01
	weights = ones((n, 1))
	for i in range(m):
		h = sigmoid(sum(dataMatrix[i] * weights))
		error = labelMat[i] - h
		weights = weights + alpha *dataMatrix[i].transpose() * error  
	return weights

# 改进的随机梯度上升算法
def stocGradAscent_optimized(dataMatIn, classLabels, numIter=150):
	# 转换为numpy矩阵数据类型
	dataMatrix = mat(dataMatIn)
	labelMat = mat(classLabels).transpose()
	m, n = shape(dataMatrix)
	weights = ones((n, 1))
	for j in range(numIter):
		dataIndex = range(m)
		for i in range(n):
			alpha = 4 / (1.0 + j + i) + 0.01
			randIndex = int(random.uniform(0, len(dataIndex)))
			h = sigmoid(sum(dataMatrix[randIndex] * weights))
			error = classLabels[randIndex] - h
			weights = weights + alpha * dataMatrix[randIndex].transpose() * error
#			del(dataIndex[randIndex])
	return weights


# Logistic回归分类函数
def classifyVector(inX, weights):
	prob = sigmoid(sum(inX * weights))
	if prob > 0.5:
		return 1
	else:
		return 0

def colicTest():
	frTrain = open('horseColicTraining.txt')
	frTest = open('horseColicTest.txt')

	trainingSet = []
	trainingLabels = []
	for line in frTrain.readlines():
		currentLine = line.strip().split('\t')
		lineArr = []
		for i in range(21):
			lineArr.append(float(currentLine[i]))
		trainingSet.append(lineArr)
		trainingLabels.append(float(currentLine[21]))

	trainWeights = stocGradAscent_optimized(trainingSet, trainingLabels, 1500)
	errorCount = 0
	numTestVec = 0
	for line in frTest.readlines():
		numTestVec += 1
		currentLine = line.strip().split('\t')
		lineArr = []
		for i in range(21):
			lineArr.append(float(currentLine[i]))
		if int(classifyVector(array(lineArr), trainWeights)) != int(currentLine[21]):
			errorCount += 1
	errorRate = float(errorCount) / numTestVec
	print('The error rate of this test is : %f'%errorRate)
	return errorRate

def multiTest():
	numTests = 10
	errorSum = 0
	for k in range(numTests):
		errorSum += colicTest()
	print('After %d iterations the average error rate is: %f'%(numTests, errorSum/float(numTests)))

if __name__ == '__main__':
	pass
